﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;


namespace MyLightControl
{
    public partial class MyLigntControl : UserControl
    {
        #region 私有字段
        private bool m_bOn;
        private Color m_onColor = Color.Lime;
        private Color m_offColor = Color.DarkGray;
        private bool m_b3D = true;
        private bool m_bBlinking = false;
        private int m_nBlinkInterval = 500;
        private Timer m_BlinkTimer;
        private bool m_bCircle = true;
        private int m_nBorderWidth = 1;
        private Color m_borderColor = Color.DarkGray;
        private bool m_temporaryState = false;
        #endregion

        #region 动画相关字段
        private bool m_bBreathing = false;
        private bool m_bRotating = false;
        private bool m_bRippling = false;
        private float m_fBreathOpacity = 1.0f;
        private float m_fRotateAngle = 0f;
        private List<float> m_rippleRadii = new List<float>();
        private float BREATHING_STEP = 0.05f;
        private float ROTATION_STEP = 2f;
        private float RIPPLE_STEP = 2f;
        private int MAX_RIPPLE = 3;
        private Timer animationTimer;
        private bool breathDirection = false; // false为淡出,false为淡入
        #endregion

        #region 属性
        [Category("Animation")]
        public bool IsBreathing
        {
            get { return m_bBreathing; }
            set
            {
                m_bBreathing = value;
                if (m_bBreathing)
                    animationTimer.Start();
                else if (!IsAnimating())
                    animationTimer.Stop();
                Invalidate();
            }
        }

        [Category("Animation")]
        public bool IsRotating
        {
            get { return m_bRotating; }
            set
            {
                m_bRotating = value;
                if (m_bRotating)
                    animationTimer.Start();
                else if (!IsAnimating())
                    animationTimer.Stop();
                Invalidate();
            }
        }

        [Category("Animation")]
        public bool IsRippling
        {
            get { return m_bRippling; }
            set
            {
                m_bRippling = value;
                if (m_bRippling)
                    animationTimer.Start();
                else
                {
                    m_rippleRadii.Clear();
                    if (!IsAnimating())
                        animationTimer.Stop();
                }
                Invalidate();
            }
        }

        [Category("Appearance")]
        public bool IsOn
        {
            get { return m_bOn; }
            set
            {
                m_bOn = value;
                Invalidate();
            }
        }

        [Category("Appearance")]
        public Color OnColor
        {
            get { return m_onColor; }
            set
            {
                m_onColor = value;
                Invalidate();
            }
        }

        [Category("Appearance")]
        public Color OffColor
        {
            get { return m_offColor; }
            set
            {
                m_offColor = value;
                Invalidate();
            }
        }

        [Category("Appearance")]
        public bool Is3D
        {
            get { return m_b3D; }
            set
            {
                m_b3D = value;
                Invalidate();
            }
        }

        [Category("Behaviour")]
        public bool IsBlinking
        {
            get { return m_bBlinking; }
            set
            {
                m_bBlinking = value;
                if (m_bBlinking)
                {
                    m_BlinkTimer.Start();
                }
                else
                {
                    m_BlinkTimer.Stop();
                    m_temporaryState = false;
                }
                Invalidate();
            }
        }

        [Category("Behaviour")]
        public int BlinkingInterval
        {
            get { return m_nBlinkInterval; }
            set
            {
                m_nBlinkInterval = value;
                m_BlinkTimer.Interval = value;
            }
        }

        [Category("Appearance")]
        public bool IsCircle
        {
            get { return m_bCircle; }
            set
            {
                m_bCircle = value;
                Invalidate();
            }
        }

        [Category("Appearance")]
        public int BorderWidth
        {
            get { return m_nBorderWidth; }
            set
            {
                m_nBorderWidth = value;
                Invalidate();
            }
        }

        [Category("Appearance")]
        public Color BorderColor
        {
            get { return m_borderColor; }
            set
            {
                m_borderColor = value;
                Invalidate();
            }
        }
        #endregion

        #region 构造函数
        public MyLigntControl()
        {
            InitializeComponent();
            SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            SetStyle(ControlStyles.UserPaint, true);
            SetStyle(ControlStyles.ResizeRedraw, true);
            Size size = new Size(30, 30);
            BackColor = Color.Transparent;
            m_BlinkTimer = new Timer();
            m_BlinkTimer.Interval = m_nBlinkInterval;
            m_BlinkTimer.Tick += OnBlinkIntervalTick;

            animationTimer = new Timer();
            animationTimer.Interval = 50;
            animationTimer.Tick += OnAnimationTick;
        }
        #endregion


        public bool IsAnimating()
        {
            return m_bBreathing || m_bRotating || m_bRippling || m_bBlinking;
        }

        void OnBlinkIntervalTick(object sender, EventArgs e)
        {
            m_temporaryState = !m_temporaryState;
            Invalidate();
        }

        void OnAnimationTick(object sender, EventArgs e)
        {
            bool bNeedInvalidate = false;
            // 呼吸效果
            if (IsBreathing)
            {
                if (breathDirection)
                {
                    m_fBreathOpacity -= BREATHING_STEP;
                    if (m_fBreathOpacity <= 0.3f)
                    {
                        m_fBreathOpacity = 0.3f;
                        breathDirection = true;
                    }
                }
                else
                {
                    m_fBreathOpacity += BREATHING_STEP;
                    if (m_fBreathOpacity >= 1.0f)
                    {
                        m_fBreathOpacity = 1.0f;
                        breathDirection = false;
                    }

                }
                bNeedInvalidate = true;
            }

            // 旋转效果
            if (IsRotating)
            {
                m_fRotateAngle = (m_fRotateAngle + ROTATION_STEP) % 360;
                bNeedInvalidate = true;
            }
            // 波纹效果
            if (IsRippling)
            {
                for (int i = m_rippleRadii.Count - 1; i >= 0; i--)
                {
                    m_rippleRadii[i] += RIPPLE_STEP;
                    if (m_rippleRadii[i] > Math.Max(Width, Height))
                    {
                        m_rippleRadii.RemoveAt(i);
                    }
                }

                if (m_rippleRadii.Count < MAX_RIPPLE && (m_rippleRadii.Count == 0 || m_rippleRadii[m_rippleRadii.Count - 1] > 20))
                {
                    m_rippleRadii.Add(0f);
                }

                bNeedInvalidate = true;
            }

            if (bNeedInvalidate)
                Invalidate();
        }

        #region 绘制方法
        private void MyLigntControl_Paint(object sender, PaintEventArgs e)
        {
            e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
            bool bCurrentState = IsBlinking ? m_temporaryState : IsOn;
            Color CurrentColor = bCurrentState ? OnColor : OffColor;

            // 应用呼吸效果的透明度
            if (IsBreathing)
            {
                CurrentColor = Color.FromArgb((int)
                    (255 * m_fBreathOpacity),
                    CurrentColor.R,
                    CurrentColor.G,
                    CurrentColor.B);
            }
            // 保存当前图形状态
            GraphicsState state = e.Graphics.Save();
            // 应用旋转
            if (IsRotating)
            {
                e.Graphics.TranslateTransform(Width / 2f, Height / 2f);
                e.Graphics.RotateTransform(m_fRotateAngle);
                e.Graphics.TranslateTransform(-Width / 2f, -Height / 2f);
            }

            using (GraphicsPath path = new GraphicsPath())
            {
                Rectangle bounds = new Rectangle(m_nBorderWidth,
                    m_nBorderWidth, Width - 2 * m_nBorderWidth - 1, Height - 2 * m_nBorderWidth - 1);

                if (IsCircle)
                    path.AddEllipse(bounds);
                else
                    path.AddRectangle(bounds);

                if (Is3D)
                {
                    using (PathGradientBrush gradientBrush = new PathGradientBrush(path))
                    {
                        gradientBrush.CenterColor = LightenColor(CurrentColor, 50);
                        gradientBrush.SurroundColors = new Color[] { CurrentColor };
                        gradientBrush.FocusScales = new PointF(0.8f, 0.8f);

                        e.Graphics.FillPath(gradientBrush, path);
                    }
                    // 高光效果
                    DrawHightLiaght(e.Graphics, bounds);
                }
                else
                {
                    using (SolidBrush brush = new SolidBrush(CurrentColor))
                    {
                        e.Graphics.FillPath(brush, path);
                    }
                }

                if (m_nBorderWidth > 0)
                {
                    using (Pen borderPen = new Pen(m_borderColor, m_nBorderWidth))
                    {
                        e.Graphics.DrawPath(borderPen, path);
                    }
                }
            }

            e.Graphics.Restore(state);

            if (IsRippling && m_rippleRadii.Count > 0)
            {
                DrawRipple(e.Graphics);
            }
            // base.OnPaint(e);
        }
        #endregion

        #region 辅助方法
        private Color LightenColor(Color color, int nAmount)
        {
            return Color.FromArgb(color.A,
               Math.Min(color.R + nAmount, 255),
               Math.Min(color.G + nAmount, 255),
               Math.Min(color.B + nAmount, 255));
        }
        #endregion 

        private void DrawHightLiaght(Graphics graphics, Rectangle bounds)
        {
            using (GraphicsPath highLightpath = new GraphicsPath())
            {
                Rectangle highLightBounds = new Rectangle(
                    bounds.X + bounds.Width / 4,
                    bounds.X + bounds.Height / 4,
                    bounds.Width / 4,
                    bounds.Height / 4
                    );

                highLightpath.AddEllipse(highLightBounds);


                using (PathGradientBrush highLightBrush = new PathGradientBrush(highLightpath))
                {
                    highLightBrush.CenterColor = Color.FromArgb(180, Color.White);
                    highLightBrush.SurroundColors = new Color[] { Color.FromArgb(0, Color.White) };

                    graphics.FillPath(highLightBrush, highLightpath);
                }

            }
        }

        private void DrawRipple(Graphics graphics)
        {
            float fCenterX = Width / 2f;
            float fCenterY = Height / 2f;

            foreach (float fRadius in m_rippleRadii)
            {
                // 计算波纹透明度
                float fAlpha = 1.0f - (fRadius / Math.Min(Width, Height));
                if (fAlpha <= 0)
                    continue;

                using (Pen pen = new Pen(Color.FromArgb((int)(fAlpha * 255), OnColor), 2))
                {
                    graphics.DrawEllipse(pen,
                            fCenterX - fRadius,
                            fCenterY - fRadius,
                            fRadius * 2,
                            fRadius * 2);



                }
            }
        }

        #region 公共方法
        public void StartBlinking()
        { 
            IsBlinking = true;
        }

        public void StopBlinking()
        {
            IsBlinking = false;
        }

        public void Toggle()
        {
            IsOn = !IsOn;
        }

        public void StartBreathing()
        {
            IsBreathing = true;
        }

        public void StopBreathing()
        {
            IsBreathing = false;
        }

        public void StartRotating()
        {
            IsRotating = true;
        }

        public void StopRotating()
        {
            IsRotating = false;
        }

        public void StartRippling()
        {
            IsRippling = true;
        }

        public void StopRippling()
        {
            IsRippling = false;
        }
        #endregion
    }
}
